<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Proxy methods</title>
  </head>
  <body></body>

  <script>
    var data = {
      foo: 1,
      get bar() {
        return this.foo + 1;
      },
    };

    var obj = new Proxy(data, {
      // 拦截对象属性的读取，比如proxy.foo和proxy['foo']
      get(target, key, receiver) {
        console.log("get", key);
        return Reflect.get(target, key, receiver);
      },
      // 拦截对象属性的设置，比如proxy.foo = v或proxy['foo'] = v，返回一个布尔值
      set(target, key, value, receiver) {
        console.log("set", key, value);
        return Reflect.set(target, key, value, receiver);
      },
      // 拦截propKey in proxy的操作，返回一个布尔值
      has(target, key) {
        console.log("has", key);
        return Reflect.has(target, key);
      },
      // 拦截delete proxy[propKey]的操作，返回一个布尔值
      deleteProperty(target, key) {
        console.log("delete", key);
        return Reflect.defineProperty(target, key);
      },
      // 拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for...in循环，返回一个数组。该方法返回目标对象所有自身的属性的属性名，而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。
      ownKeys(target) {
        console.log("ownKeys");
        return Reflect.ownKeys(target);
      },
      // 拦截Object.getOwnPropertyDescriptor(proxy, propKey)，返回属性的描述对象。
      getOwnPropertyDescriptor(target, key) {
        console.log("getOwnPropertyDescriptor", key);
        return Reflect.getOwnPropertyDescriptor(target, key);
      },
      // 拦截Object.defineProperty(proxy, propKey, propDesc）、Object.defineProperties(proxy, propDescs)，返回一个布尔值。
      defineProperty(target, key, descriptor) {
        console.log("defineProperty", key, descriptor);
        Reflect.defineProperty(target, key, descriptor);
      },
      // 拦截Object.getPrototypeOf(proxy)，返回一个对象。
      getPrototypeOf(target) {
        console.log("getPrototypeOf");
        return Reflect.getPrototypeOf(target);
      },
      // 拦截Object.setPrototypeOf(proxy, proto)，返回一个布尔值。如果目标对象是函数，那么还有两种额外操作可以拦截。
      setPrototypeOf(target, proto) {
        console.log("setPrototypeOf", proto);
        Reflect.setPrototypeOf(target, proto);
      },
      // 拦截Object.isExtensible(proxy)，返回一个布尔值。
      isExtensible(target) {
        console.log("isExtensible");
        return Reflect.isExtensible(target);
      },
      // 拦截Object.preventExtensions(proxy)，返回一个布尔值。
      preventExtensions(target) {
        console.log("preventExtensions");
        return Reflect.preventExtensions(target);
      },
      // 拦截 Proxy 实例作为函数调用的操作，比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。
      apply(target, thisArg, args) {
        console.log("apply", args);
        return Reflect.apply(target, thisArg, args);
      },
      // 拦截 Proxy 实例作为构造函数调用的操作，比如new proxy(...args)。
      construct(target, args) {
        console.log("construct", args);
        return Reflect.construct(target, args);
      },
    });

    // console.log(obj.foo, obj.bar);
    // obj.foo;
    // obj.bar;
    // "foo" in obj;
    // for (const key in obj) {
    // }
    for (const key of obj) {
    }
  </script>
</html>
